package com.github.llyb120.calengine.rule;

import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import com.alibaba.fastjson.JSONObject;
import com.github.llyb120.calengine.entity.ScopeData;
import com.github.llyb120.calengine.parser.DatasourceParser;
import com.github.llyb120.performance.define.*;
import lombok.Cleanup;
import lombok.SneakyThrows;
import org.beetl.sql.core.SQLBatchReady;
import org.beetl.sql.core.SQLManager;
import org.beetl.sql.core.SQLReady;

import javax.xml.crypto.Data;
import java.io.File;
import java.util.*;
import java.util.stream.Collectors;

public class DatasetWrapper extends Dataset {

    private RuleEngine ruleEngine;
    private Dataset innerObject;
    
    public DatasetWrapper(RuleEngine ruleEngine, Dataset dataset) {
        this.ruleEngine = ruleEngine;
        this.innerObject = dataset;
    }


    @SneakyThrows
    public void importData(List<Map> importData, boolean clear){
        SQLManager sqlManager = null;
        if(clear){
            DatasourceWrapper datasourceWrapper = ruleEngine.getDatasource(getLead().getUse());
            sqlManager = datasourceWrapper.getSqlManager();
            sqlManager.executeUpdate(new SQLReady(String.format("delete from %s", getLead().getTable())));
        }
        List<Object[]> data = new ArrayList<>();
        for (Map<String, Object> map : importData) {
            Object[] objects = new Object[getField().size()];
            int i = 0;
            for (Field field : getField()) {
                Converter converter = ruleEngine.getConverter(field.getConverter());
                Object value = map.get(field.getEn());
                if (value == null) {
                    value = map.get(field.getCn());
                }
                value = convertInput(converter, value);
                objects[i++] = value;
            }
            data.add(objects);
        }
        if(data.isEmpty()){
            return;
        }
        String sql = String.format("insert into `%s` (%s) values (%s)",
                getLead().getTable(),
                getField().stream().map(e -> "`" + e.getEn() + "`").collect(Collectors.joining(",")),
                getField().stream().map(e -> "?").collect(Collectors.joining(","))
        );
        if (sqlManager == null) {
            DatasourceWrapper datasourceWrapper = ruleEngine.getDatasource(getLead().getUse());
            sqlManager = datasourceWrapper.getSqlManager();
        }
        SQLBatchReady ready = new SQLBatchReady(sql, data);
        sqlManager.executeBatchUpdate(ready);
    }

    public List<ScopeData> calculateScope(){
        DatasourceWrapper datasourceRule = ruleEngine.getDatasource(getScope().getUse());
        SQLManager sqlManager = datasourceRule.getSqlManager();
        List<JSONObject> result = sqlManager.execute(new SQLReady(getScope().getSql()), JSONObject.class);
        //group
        Map<String, ScopeData> ret = new LinkedHashMap<>();
        for (JSONObject item : result) {
            StringJoiner sj = new StringJoiner("-");
            for (String s : getScope().getGroup()) {
                sj.add(item.getString(s));
            }
            String key = sj.toString();
            ScopeData scopeData = ret.get(key);
            if (scopeData == null) {
                scopeData = ScopeData.builder()
                        .name(key)
                        .data(new ArrayList())
                        .build();
                ret.put(key, scopeData);
            }
            ((List)scopeData.getData()).add(item);
        }
        return new ArrayList<>(ret.values());
    }



    private Object convertInput(Converter converter, Object data){
        if (converter == null) {
            return data;
        }
        if (converter.getInput() == null) {
            return data;
        }
        return converter.getInput().call(data);
    }




    /*********************************************/

    @Override
    public String getName() {
        return innerObject.getName();
    }

    @Override
    public void setName(String name) {
        innerObject.setName(name);
    }

    @Override
    public List<Field> getField() {
        return innerObject.getField();
    }

    @Override
    public void setField(List<Field> field) {
        innerObject.setField(field);
    }

    @Override
    public Scope getScope() {
        return innerObject.getScope();
    }

    @Override
    public void setScope(Scope scope) {
        innerObject.setScope(scope);
    }

    @Override
    public Lead getLead() {
        return innerObject.getLead();
    }

    @Override
    public void setLead(Lead lead) {
        innerObject.setLead(lead);
    }
}
